﻿using AntdUI;
using AntdUIDemo.Utils;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Features2D;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using OcrAnswerQuestionsForm;
using OcrLiteLib;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WuXiaOcrAQ;

namespace OcrLiteOnnxCs
{
    public partial class FormOcrLite : AntdUI.Window
    {
        private OcrLite ocrEngin;
        private byte[] imageData; // 存储截图的内存数据

        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rectangle rect);
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
        [DllImport("gdi32.dll")]
        private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
        [DllImport("gdi32.dll")]
        private static extern int DeleteDC(IntPtr hdc);
        [DllImport("user32.dll")]
        private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, int nFlags);
        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowDC(IntPtr hwnd);
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        // 获得本窗体的句柄
        public static extern IntPtr GetForegroundWindow();
        [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
        // 设置此窗体为活动窗体
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);


        private int padding = 50;
        private int imgResize = 1600;
        private float boxScoreThresh = 0.618F;
        private float boxThresh = 0.300F;
        private float unClipRatio = 2.0F;
        private bool doAngle = true;
        private bool mostAngle = true;
        float scalingFactor = 1.5f;

        public FormOcrLite()
        {
            InitializeComponent();
            //AutoDpi(this);

            ThemeHelper.SetColorMode(this, true);
            //初始化消息弹出位置
            Config.ShowInWindow = true;

            buttonSZ.Click += button1_Click;
            buttonSZ2.Click += button5_Click;
            buttonSZ3.Click += button7_Click;

            using (Graphics g = this.CreateGraphics())
            {
                float dpiX = g.DpiX;
                scalingFactor = dpiX / 96.0f;
            }
        }

        private void FormOcrLite_Load(object sender, EventArgs e)
        {
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            var appPath = AppDomain.CurrentDomain.BaseDirectory;
            var modelsDir = appPath + "models";
            var detPath = $"{modelsDir}\\{ConfigSettings.ReadSetting("detNameTextBox")}";
            var clsPath = $"{modelsDir}\\{ConfigSettings.ReadSetting("clsNameTextBox")}";
            var recPath = $"{modelsDir}\\{ConfigSettings.ReadSetting("recNameTextBox")}";
            var keysPath = $"{modelsDir}\\{ConfigSettings.ReadSetting("keysNameTextBox")}";
            var isDetExists = File.Exists(detPath);
            if (!isDetExists)
            {
                MessageBox.Show($@"模型文件不存在:{detPath}");
            }
            var isClsExists = File.Exists(clsPath);
            if (!isClsExists)
            {
                MessageBox.Show($@"模型文件不存在:{clsPath}");
            }
            var isRecExists = File.Exists(recPath);
            if (!isRecExists)
            {
                MessageBox.Show($@"模型文件不存在:{recPath}");
            }
            var isKeysExists = File.Exists(keysPath);
            if (!isKeysExists)
            {
                MessageBox.Show($@"Keys文件不存在:{keysPath}");
            }
            if (isDetExists && isClsExists && isRecExists && isKeysExists)
            {
                ocrEngin = new OcrLite();

                int.TryParse(ConfigSettings.ReadSetting("numThreadNumeric"), out var iValue);
                ocrEngin.InitModels(detPath, clsPath, recPath, keysPath, iValue);
            }
            else
            {
                MessageBox.Show(@"初始化失败，请确认模型文件夹和文件后，重新初始化！");
            }


            // 初始化Ocr
            int.TryParse(ConfigSettings.ReadSetting("paddingNumeric"), out padding);
            int.TryParse(ConfigSettings.ReadSetting("imgResizeNumeric"), out imgResize);

            float.TryParse(ConfigSettings.ReadSetting("boxScoreThreshNumeric"), out boxScoreThresh);
            float.TryParse(ConfigSettings.ReadSetting("boxThreshNumeric"), out boxThresh);
            float.TryParse(ConfigSettings.ReadSetting("unClipRatioNumeric"), out unClipRatio);

            bool.TryParse(ConfigSettings.ReadSetting("doAngleCheckBox"), out doAngle);
            bool.TryParse(ConfigSettings.ReadSetting("mostAngleCheckBox"), out mostAngle);

            // 初始化大小
            Width = (int)(1045 * scalingFactor)  ;
            Height = (int)(391 * scalingFactor);

            // 736, 279

            // 初始化答案数据
            InitData();

            //设置时间间隔ms
            var interval = Convert.ToInt32(textBox3.Text);
            timer1.Interval = interval;
            timer1.Start();
        }

        private bool bRun;
        //private void timer1_Tick(object sender, EventArgs e)
        //{
        //    if (!bEnable || bRun) return;
        //    bRun = true;
        //    GetImg();
        //    CalcA();
        //    // Show  textBox1.Text
        //    if (string.IsNullOrEmpty(textBox2.Text))
        //    {
        //        var messageForm = MessageForm.CreateForm();
        //        messageForm.label1.Text = textBox1.Text;
        //        if (markAnchorPointX > 0 && markAnchorPointY > 0)
        //        {
        //            messageForm.label2.Location = new Point(markAnchorPointX - 100, markAnchorPointY + 200);
        //        }
        //        else
        //        {
        //            messageForm.label2.Location = new Point(markAnchorPointX, markAnchorPointY + 200);
        //        }
        //        messageForm.Show();
        //    }

        //    bRun = false;
        //}
        private async void timer1_Tick(object sender, EventArgs e)
        {
            if (!bEnable || bRun) return;

            bRun = true;

            //messageForm.label1.Text = "待解析";
            // 获取图片和计算逻辑放到后台线程中执行
            await Task.Run(() =>
            {
                GetImg();
                CalcA();
            });

            // 回到 UI 线程更新界面
            if (string.IsNullOrEmpty(textBox2.Text))
            {
                var messageForm = MessageForm.CreateForm();
                messageForm.label1.Text = textBox1.Text;

                if (markAnchorPointX > 0 && markAnchorPointY > 0)
                {
                    messageForm.labelExt1.Location = new Point((int)(markAnchorPointX - (100 * scalingFactor)), (int)(markAnchorPointY + (200 * scalingFactor)));
                }
                else
                {
                    messageForm.labelExt1.Location = new Point(markAnchorPointX, (int)(markAnchorPointY + (200 * scalingFactor)));
                }

                messageForm.Show();
            }

            bRun = false;
        }
        private void openBtn_Click(object sender, EventArgs e)
        {
            using (var dlg = new OpenFileDialog())
            {
                dlg.Multiselect = false;
                dlg.Filter = @"(*.JPG,*.PNG,*.JPEG,*.BMP,*.GIF)|*.JPG;*.PNG;*.JPEG;*.BMP;*.GIF|All files(*.*)|*.*";
                if (dlg.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(dlg.FileName)) return;
                pathTextBox.Text = dlg.FileName;
                var src = CvInvoke.Imread(dlg.FileName);
                pictureBox.Image = src.ToBitmap();
            }
        }

        private void detectBtn_Click(object sender, EventArgs e)
        {
            CalcA();
        }

        private string strOldQ = string.Empty;
        private string strOldA = string.Empty;

        private int markAnchorPointX;
        private int markAnchorPointY;
        private void CalcA()
        {
            if (textBox1.InvokeRequired)
            {
                textBox1.Invoke(new MethodInvoker(delegate {
                    textBox1.Text = string.Empty;
                }));
            }
            else
            {
                textBox1.Text = string.Empty;
            }

            if (textBox2.InvokeRequired)
            {
                textBox2.Invoke(new MethodInvoker(delegate {
                    textBox2.Text = string.Empty;
                }));
            }
            else
            {
                textBox2.Text = string.Empty;
            }


            var sw = new Stopwatch();
            sw.Start();
            var sw1 = new Stopwatch();
            sw1.Start();

            if (ocrEngin == null)
            {
                MessageBox.Show(@"未初始化，无法执行!");
                return;
            }
            //string targetImg = string.IsNullOrEmpty(pathTextBox.Text) ? "temp.jpg" : pathTextBox.Text;
            //if (!File.Exists(targetImg))
            //{
            //    MessageBox.Show(@"目标图片不存在，请用Open按钮打开");
            //    return;
            //}
            //var ocrResult = ocrEngin.Detect(targetImg, padding, imgResize, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
            // ... existing code ...
            Mat targetImg;
            if (string.IsNullOrEmpty(pathTextBox.Text))
            {
                if (imageData == null)
                {
                    MessageBox.Show(@"未找到截图数据，请先进行截图");
                    return;
                }

                // 从内存数据创建Bitmap
                using (MemoryStream ms = new MemoryStream(imageData))
                {
                    using (Bitmap bitmap = new Bitmap(ms))
                    {
                        targetImg = bitmap.ToMat();
                    }
                }
            }
            else
            {
                targetImg = CvInvoke.Imread(pathTextBox.Text, ImreadModes.Color);
            }

            var ocrResult = ocrEngin.DetectFromMat(targetImg, padding, imgResize, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
            //ocrResultTextBox.Text = ocrResult.ToString();
            //strRestTextBox.Text = ocrResult.StrRes;
            if (strRestTextBox.InvokeRequired)
            {
                strRestTextBox.Invoke(new MethodInvoker(delegate {
                    strRestTextBox.Text = ocrResult.StrRes;
                }));
            }
            else
            {
                strRestTextBox.Text = ocrResult.StrRes;
            }

            pictureBox.Image = ocrResult.BoxImg.ToBitmap();

            // 获取题目内容
            var titleCont = -1;
            var titleContW = -1;
            ocrResult.TextBlocks.RemoveAll(tb => tb.Text.TrimStart().StartsWith("进度"));
            for (var i = 0; i < ocrResult.TextBlocks.Count; i++)
            {
                var strLine = ocrResult.TextBlocks[i].Text;
                var lstQOcr = new List<string>
                {
                    "题目",
                    "题自",
                    "简山",
                    "强山",
                    "暂日",
                    "假四",
                    "暂丽",
                    "题丽",
                    "新色",
                    "窗卫",
                    "商工",
                    "当日",
                    "背工"
                };

                if (lstQOcr.Contains(strLine) || (strLine.Length == 2 && strLine.Contains("题")))
                {
                    titleCont = i;
                }

                if (!strLine.Contains("根据题")) continue;
                titleContW = i;
                break;
            }

            // 根据横向坐标进行误数据清理
            if (titleCont >= 0)
            {
                textBox2.Text = string.Empty;
                if (ocrResult.TextBlocks[titleCont].BoxPoints.Count > 2)
                {
                    var iQBoxPointX1 = ocrResult.TextBlocks[titleCont].BoxPoints[0].X;
                    var iQBoxPointY3 = ocrResult.TextBlocks[titleCont].BoxPoints[2].Y;
                    for (var i = 1; i < 10; i++)
                    {
                        //if (!string.IsNullOrEmpty(textBox2.Text))
                        //{
                        //    break;
                        //}
                        if (i >= (titleContW - titleCont))
                        {
                            break;
                        }

                        if (ocrResult.TextBlocks.Count <= titleCont + i) continue;
                        if (ocrResult.TextBlocks[titleCont + i].BoxPoints.Count <= 0) continue;
                        var iABoxPointX1 = ocrResult.TextBlocks[titleCont + i].BoxPoints[0].X;
                        var iABoxPointY3 = ocrResult.TextBlocks[titleCont + i].BoxPoints[2].Y;
                        // 横向偏移100
                         int iXOffset = (int)(400 * scalingFactor);
                        // 纵向偏移50
                         int iYOffset = (int)(150 * scalingFactor);
                        if (iABoxPointX1 >= iQBoxPointX1 - 10 * scalingFactor && iABoxPointX1 <= iQBoxPointX1 + iXOffset)
                        {
                            if (iABoxPointY3 >= iQBoxPointY3 - 10 * scalingFactor &&
                                iABoxPointY3 <= iQBoxPointY3 + iYOffset)
                            {
                                var strQ = ocrResult.TextBlocks[titleCont + i].Text;
                                // 有几个字数特别少的，解析失败率极高
                                if (strQ == "车轶轶，马带着，" || strQ == "车轶轶，马前着，")
                                {
                                    strQ = "车辚辚，马萧萧，";
                                }

                                if (strQ.Contains("茕") &&  strQ.Length < 10)
                                {
                                    strQ = "茕茕孑立";
                                }

                                if (strQ.Contains("斗酒") && strQ.Length > 5 && strQ.Length < 10)
                                {
                                    strQ = "斗酒十千恣欢谑";
                                }

                                if (textBox2.InvokeRequired)
                                {
                                    textBox2.Invoke(new MethodInvoker(delegate {
                                        textBox2.Text += strQ;
                                    }));
                                }
                                else
                                {
                                    textBox2.Text += strQ;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate {
                        textBox1.Text = @"题目解析失败！";
                    }));
                }
                else
                {
                    textBox1.Text = @"题目解析失败！";
                }
            }
            sw.Stop();
            var ts2 = sw.Elapsed; 
            if (label15.InvokeRequired)
            {
                label15.Invoke(new MethodInvoker(delegate {
                    label15.Text = $@"题目解析用时：{ts2.TotalMilliseconds} 毫秒";
                }));
            }
            else
            {
                label15.Text = $@"题目解析用时：{ts2.TotalMilliseconds} 毫秒";
            }

            var sw2 = new Stopwatch();
            sw2.Start();
            // 如果题目没变，则不进行答案解析
            var sims = new SimilarityalgorithmTool();

            var strOcrQ = RetainChineseString(textBox2.Text);
            strOcrQ = strOcrQ.Replace("进度", string.Empty);
            var com = sims.CompareStrings(strOcrQ, RetainChineseString(strOldQ));
            if (com <= 0.8)
            {
                markAnchorPointX = 0;
                markAnchorPointY = 0;
                var messageForm = MessageForm.CreateForm();
                SafeCloseForm(messageForm);
                if (titleCont >= 0)
                {
                    // 获取当前窗体的 Graphics 对象的 DPI 设置
                    //using (Graphics g = this.CreateGraphics())
                    //{
                        markAnchorPointX = (int)(ocrResult.TextBlocks[titleCont].BoxPoints[0].X * scalingFactor);
                        markAnchorPointY = (int)(ocrResult.TextBlocks[titleCont].BoxPoints[0].Y * scalingFactor);
                    //}

                    //markAnchorPointX = (int)(ocrResult.TextBlocks[titleCont].BoxPoints[0].X * 1.5);
                    //markAnchorPointY = (int)(ocrResult.TextBlocks[titleCont].BoxPoints[0].Y * 1.5);
                }
                GetAns();
            }
            else
            {
                if (!string.IsNullOrEmpty(strOldA))
                {
                    if (textBox1.InvokeRequired)
                    {
                        textBox1.Invoke(new MethodInvoker(delegate {
                            textBox1.Text = strOldA;
                        }));
                    }
                    else
                    {
                        textBox1.Text = strOldA;
                    }
                }
            }

            strOldQ = textBox2.Text;
            strOldA = textBox1.Text;
            sw2.Stop();
            var ts3 = sw2.Elapsed;
            if (label16.InvokeRequired)
            {
                label16.Invoke(new MethodInvoker(delegate {
                    label16.Text = $@"答案解析用时：{ts3.TotalMilliseconds:F2} 毫秒";
                }));
            }
            else
            {
                label16.Text = $@"答案解析用时：{ts3.TotalMilliseconds:F2} 毫秒";
            }

            if (string.IsNullOrEmpty(textBox1.Text))
            {
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate {
                        textBox1.Text = @"匹配答案失败！";
                    }));
                }
                else
                {
                    textBox1.Text = @"匹配答案失败！";
                }
            }
            sw1.Stop();
            var ts4 = sw1.Elapsed;
            if (label17.InvokeRequired)
            {
                label17.Invoke(new MethodInvoker(delegate {
                    label17.Text = $@"总解析用时：{ts4.TotalMilliseconds:F2} 毫秒";
                }));
            }
            else
            {
                label17.Text = $@"总解析用时：{ts4.TotalMilliseconds:F2} 毫秒";
            }
        }

        public void SafeCloseForm(Form form)
        {
            if (form == null || form.IsDisposed || form.Disposing)
                return;

            if (form.InvokeRequired)
            {
                try
                {
                    form.BeginInvoke(new MethodInvoker(() =>
                    {
                        if (!form.IsDisposed && !form.Disposing)
                        {
                            form.Close();
                        }
                    }));
                }
                catch (Exception ex) when (ex is System.ComponentModel.InvalidAsynchronousStateException ||
                                           ex is System.Threading.ThreadStateException)
                {
                    Console.WriteLine("无法安全关闭窗体：" + ex.Message);
                }
            }
            else
            {
                form.Close();
            }
        }


        private void GetAns()
        {
            if (string.IsNullOrEmpty(textBox2.Text))
            {
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate {
                        textBox1.Text = @"答案匹配失败！题目文本为空！";
                    }));
                }
                else
                {
                    textBox1.Text = @"答案匹配失败！题目文本为空！";
                }
                return;
            }
            // 使用文本匹配路径获取相似度答案
            var dt = dataGridView1.DataSource as DataTable;
            var sims = new SimilarityalgorithmTool();

            // 选取5个排序
            var lstDr = new List<DataRow>();
            var lstCom = new List<double>();
            var lstIndex = new List<int>();
            var bHigh = false;
            for (var i = 0; i < dt.Rows.Count; i++)
            {
                var dr = dt.Rows[i];
                var strQ = RetainChineseString(Convert.ToString(dr["q"]));

                if ((textBox2.Text.StartsWith("，") || textBox2.Text.StartsWith(","))
                    && !strQ.Contains("_，"))
                {
                    continue;
                }

                var strOcrQ = RetainChineseString(textBox2.Text).Replace("进度", string.Empty);
                var com = Math.Round(sims.CompareStrings(strOcrQ, strQ), 2);

                // 提高匹配率：拆分“，”处理
                if (strQ.Contains("，"))
                {
                    var arr = strQ.Split('，');
                    com = arr.Select(item => Math.Round(sims.CompareStrings(strOcrQ, item), 2))
                             .Concat(new[] { com }).Max();
                }

                if (com > 0.9)
                {
                    var strA = Convert.ToString(dr["l"]);
                    var iA = Convert.ToInt32(dr["a"]);
                    var arr = strA.Split(',');

                    if (iA > 0 && iA <= arr.Length)
                    {
                        // 安全更新 textBox1.Text
                        if (textBox1.InvokeRequired)
                        {
                            textBox1.Invoke(new MethodInvoker(delegate {
                                //textBox1.Text = $@"答案选项为：  {arr[iA - 1]}  ,第{iA}个,文本路径匹配度：{com}";

                                textBox1.Text = $"{iA}{iA}{iA}{iA}-----{arr[iA - 1]}";
                            }));
                        }
                        else
                        {
                            textBox1.Text = $"{iA}{iA}{iA}{iA}-----{arr[iA - 1]}";
                        }

                        // 创建并设置 messageForm 必须也在主线程执行
                        if (this.InvokeRequired)
                        {
                            this.Invoke(new MethodInvoker(delegate
                            {
                                ShowMessageForm(arr, iA, markAnchorPointX, markAnchorPointY);
                            }));
                        }
                        else
                        {
                            ShowMessageForm(arr, iA, markAnchorPointX, markAnchorPointY);
                        }

                        bHigh = true;
                        break;
                    }
                }

                if (com > 0.43)
                {
                    lstDr.Add(dr);
                    lstCom.Add(com);
                    lstIndex.Add(i);
                }
            }
            if (!bHigh)
            {
                //textBox1.Text = "";
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate {
                        textBox1.Text = "";
                    }));
                }
                else
                {
                    textBox1.Text = "";
                }
            }

            if (!string.IsNullOrEmpty(textBox1.Text) || lstDr.Count <= 0) return;
            {
                var max = lstCom.Max(t => t);
                var lstAns = new List<Answer>();
                var lstAns2 = new List<Answer>();
                for (var i = 0; i < lstCom.Count; i++)
                {
                    var item = lstCom[i];
                    if (item == max)
                    {
                        var strA = Convert.ToString(lstDr[i]["l"]);
                        var iA = Convert.ToInt32(lstDr[i]["a"]);
                        var arr = strA.Split(',');
                        if (arr.Length < iA || iA <= 0) continue;
                        var answer = new Answer
                        {
                            Text = arr[iA - 1],
                            IsMain = true,
                            MatchingDegree = item,
                            Option = iA,
                            ProblemIndex = lstIndex[i]
                        };
                        lstAns.Add(answer);
                    }
                    else
                    {
                        var strA = Convert.ToString(lstDr[i]["l"]);
                        var iA = Convert.ToInt32(lstDr[i]["a"]);
                        var arr = strA.Split(',');
                        if (arr.Length < iA || iA <= 0) continue;
                        var answer = new Answer
                        {
                            Text = arr[iA - 1],
                            IsMain = true,
                            MatchingDegree = item,
                            Option = iA,
                            ProblemIndex = lstIndex[i]
                        };
                        lstAns.Add(answer);
                    }
                }
                // 去重
                lstAns = lstAns.Distinct().ToList();
                for (var i = lstAns.Count - 1; i >= 0; i--)
                {
                    var lst = lstAns.FindAll(x => x.Text.Equals(lstAns[i].Text) && x.Option.Equals(lstAns[i].Option));
                    if (lst.Count > 1)
                    {
                        lstAns.Remove(lstAns[i]);
                    }
                }
                lstAns2 = lstAns2.Distinct().ToList();
                // 排序
                lstAns = lstAns.OrderByDescending(a => a.MatchingDegree).ToList();
                lstAns2 = lstAns2.OrderByDescending(a => a.MatchingDegree).ToList();
                // 显示
                foreach (var item in lstAns)
                {
                    //var strA = $"主选选项为：  {item.Text}  ,第{item.Option}个,文本路径匹配度为：{item.MatchingDegree}";
                    var strA = $"{item.Option}{item.Option}{item.Option}{item.Option}-----{item.Text}";
                    if (string.IsNullOrEmpty(textBox1.Text))
                    {
                        if (textBox1.InvokeRequired)
                        {
                            textBox1.Invoke(new MethodInvoker(delegate {
                                textBox1.Text = strA;
                            }));
                        }
                        else
                        {
                            textBox1.Text = strA;
                        }
                        var messageForm = MessageForm.CreateForm();
                        if (markAnchorPointX > 0 && markAnchorPointY > 0)
                        {
                            if (messageForm.label1.InvokeRequired)
                            {
                                messageForm.label1.Invoke(new MethodInvoker(delegate {
                                    messageForm.label1.Text = textBox1.Text;
                                }));
                            }
                            else
                            {
                                messageForm.label1.Text = textBox1.Text;
                            }

                            if (messageForm.label3.InvokeRequired)
                            {
                                messageForm.label3.Invoke(new MethodInvoker(delegate {
                                    messageForm.label3.Text = $@"辅：{item.Text}";
                                }));
                            }
                            else
                            {
                                messageForm.label3.Text = $@"辅：{item.Text}";
                            }

                            const int iX = -40;
                            var iY = 79;
                            switch (item.Option)
                            {
                                case 1:
                                    iY = (int)(67 * scalingFactor);
                                    break;
                                case 2:
                                    iY = (int)(103 * scalingFactor);
                                    break;
                                case 3:
                                    iY = (int)(139 * scalingFactor);
                                    break;
                                case 4:
                                    iY = (int)(175 * scalingFactor);
                                    break;
                            }

                            //messageForm.label3.Location = new Point(markAnchorPointX + iX, markAnchorPointY + iY);
                            //messageForm.label2.Location = new Point(markAnchorPointX - 50, markAnchorPointY + 230);


                            if (messageForm.label3.InvokeRequired)
                            {
                                messageForm.label3.Invoke(new MethodInvoker(delegate {
                                    messageForm.label3.Location = new Point(markAnchorPointX + iX, markAnchorPointY + iY);
                                }));
                            }
                            else
                            {
                                messageForm.label3.Location = new Point(markAnchorPointX + iX, markAnchorPointY + iY);
                            }

                            if (messageForm.labelExt1.InvokeRequired)
                            {
                                messageForm.labelExt1.Invoke(new MethodInvoker(delegate {
                                    messageForm.labelExt1.Location = new Point(markAnchorPointX - (int)(50 * scalingFactor), markAnchorPointY + (int)(230 * scalingFactor));
                                }));
                            }
                            else
                            {
                                messageForm.labelExt1.Location = new Point(markAnchorPointX - (int)(50 * scalingFactor), markAnchorPointY + (int)(230 * scalingFactor));
                            }

                            if (messageForm.InvokeRequired)
                            {
                                messageForm.Invoke(new MethodInvoker(delegate
                                {
                                    messageForm.Show();
                                }));
                            }
                            else
                            {
                                messageForm.Show();
                            }
                        }
                        else
                        {
                            //messageForm.label2.Location = new Point(markAnchorPointX, markAnchorPointY);
                            if (messageForm.labelExt1.InvokeRequired)
                            {
                                messageForm.labelExt1.Invoke(new MethodInvoker(delegate {
                                    messageForm.labelExt1.Location = new Point(markAnchorPointX, markAnchorPointY);
                                }));
                            }
                            else
                            {
                                messageForm.labelExt1.Location = new Point(markAnchorPointX, markAnchorPointY);
                            }
                        }
                    }
                    else
                    {
                        if (textBox1.InvokeRequired)
                        {
                            textBox1.Invoke(new MethodInvoker(delegate {
                                textBox1.Text = textBox1.Text + Environment.NewLine + strA;
                            }));
                        }
                        else
                        {
                            textBox1.Text = textBox1.Text + Environment.NewLine + strA;
                        }
                    }
                }
                for (var i = 0; i < lstAns2.Count; i++)
                {
                    if (i >= 2)
                    {
                        break;
                    }
                    var item = lstAns2[i];
                    //var strA = $"备选选项为：  {item.Text}  ,第{item.Option}个,文本路径匹配度为：{item.MatchingDegree}";
                    var strA = $"{item.Option}{item.Option}{item.Option}{item.Option}-----{item.Text}";
                    var lst = lstAns.FindAll(x => x.Text.Equals(lstAns[i].Text) && x.Option.Equals(lstAns[i].Option));
                    if (lst.Count > 0)
                    {
                        continue;
                    }

                    if (string.IsNullOrEmpty(textBox1.Text))
                    {
                        if (textBox1.InvokeRequired)
                        {
                            textBox1.Invoke(new MethodInvoker(delegate {
                                textBox1.Text = strA;
                            }));
                        }
                        else
                        {
                            textBox1.Text = strA;
                        }
                    }
                    else
                    {
                        if (textBox1.InvokeRequired)
                        {
                            textBox1.Invoke(new MethodInvoker(delegate {
                                textBox1.Text = textBox1.Text + Environment.NewLine + strA;
                            }));
                        }
                        else
                        {
                            textBox1.Text = textBox1.Text + Environment.NewLine + strA;
                        }
                    }
                }
                if (string.IsNullOrEmpty(textBox1.Text))
                {
                    if (textBox1.InvokeRequired)
                    {
                        textBox1.Invoke(new MethodInvoker(delegate {
                            textBox1.Text = @"匹配答案失败！";
                        }));
                    }
                    else
                    {
                        textBox1.Text = @"匹配答案失败！";
                    }
                }
            }
        }

        private void ShowMessageForm(string[] arr, int iA, int x, int y)
        {
            // 获取当前同步上下文（用于判断是否在主线程）
            var currentContext = SynchronizationContext.Current;

            // 主窗体或任意已存在的 Control 实例，用于 Invoke 检查
            // 假设 this 是主窗体
            if (this.InvokeRequired)
            {
                // 当前是非 UI 线程，使用 BeginInvoke 回到主线程执行
                this.BeginInvoke(new Action(() => ShowMessageForm(arr, iA, x, y)));
                return;
            }

            // 以下代码保证运行在 UI 线程中

            var messageForm = MessageForm.CreateForm();

            if (x > 0 && y > 0)
            {
                messageForm.label1.Text = textBox1.Text;
                messageForm.label3.Text = $@"主：{arr[iA - 1]}";

                int iY = 79;
                switch (iA)
                {
                    case 1: iY = (int)(67 * scalingFactor); break;
                    case 2: iY = (int)(103 * scalingFactor); break;
                    case 3: iY = (int)(139 * scalingFactor); break;
                    case 4: iY = (int)(175 * scalingFactor); break;
                }

                messageForm.label3.Location = new Point(x - (int)(40 * scalingFactor), y + iY);
                messageForm.labelExt1.Location = new Point(x - (int)(50 * scalingFactor), y + (int)(230 * scalingFactor));
                messageForm.Show();
            }
            else
            {
                messageForm.labelExt1.Location = new Point(x, y);
                messageForm.Show();
            }
        }


        /// <summary>
        /// 保留中文字符串
        /// </summary>
        /// <returns></returns>
        public string RetainChineseString(string str)
        {
            var chineseString = new StringBuilder();
            foreach (var t in str.Where(t => t >= 0x4E00 && t <= 0x9FA5))
            {
                chineseString.Append(t);
            }
            return chineseString.Length > 0 ? chineseString.ToString() : string.Empty;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            GetImg();
        }

        // Temp
        //private void GetImg()
        //{
        //    try
        //    {
        //        Mat templateImage = CvInvoke.Imread("template.png", ImreadModes.Grayscale);
        //        Mat screenColor = CaptureScreen(); 
        //        Mat screenCapture = new Mat();
        //        CvInvoke.CvtColor(screenColor, screenCapture, ColorConversion.Bgr2Gray);
        //        Mat result = new Mat();
        //        CvInvoke.MatchTemplate(screenCapture, templateImage, result, TemplateMatchingType.CcoeffNormed);
        //        double minVal = 0, maxVal = 0;
        //        Point minLoc = new Point(), maxLoc = new Point();
        //        CvInvoke.MinMaxLoc(result, ref minVal, ref maxVal, ref minLoc, ref maxLoc);
        //        Rectangle matchRect = new Rectangle(maxLoc, templateImage.Size);

        //        // 容错边距
        //        int margin = 80;

        //        Rectangle safeRect = new Rectangle(
        //            Math.Max(0, matchRect.X - margin), 
        //            Math.Max(0, matchRect.Y), 
        //            Math.Min(matchRect.Width + 2 * margin, screenCapture.Width - (matchRect.X - margin)), 
        //            Math.Min(matchRect.Height, screenCapture.Height - matchRect.Y) 
        //        );

        //        if (safeRect.Right > screenCapture.Width)
        //        {
        //            safeRect.Width -= safeRect.Right - screenCapture.Width;
        //        }

        //        Mat questionArea = new Mat(screenCapture, safeRect);

        //        try
        //        {
        //            questionArea.Save("temp.jpg");
        //            pictureBox.Image = questionArea.ToBitmap();
        //        }
        //        catch (ApplicationException ex)
        //        {
        //            throw new ApplicationException(@"保存缩略图异常。", ex);
        //        }
        //        questionArea.Dispose();
        //    }
        //    catch (ApplicationException ex)
        //    {
        //        throw new ApplicationException(@"保存临时图异常。", ex);
        //    }
        //}

        private void GetImg()
        {
            try
            {
                // 1. 加载模板图像并转灰度
                Mat templateImage = CvInvoke.Imread("template.png", ImreadModes.Grayscale);
                if (templateImage.IsEmpty)
                     showinfo("模板图像加载失败");

                // 2. 截图并转灰度
                Mat screenColor = CaptureScreen();
                Mat screenCapture = new Mat();
                CvInvoke.CvtColor(screenColor, screenCapture, ColorConversion.Bgr2Gray);

                // 3. 初始化 ORB 特征检测器
                ORB orb = new ORB(1000); // 提取最多1000个关键点

                // 4. 提取模板图像和屏幕图像的关键点和描述子
                VectorOfKeyPoint templateKeypoints = new VectorOfKeyPoint();
                VectorOfKeyPoint screenKeypoints = new VectorOfKeyPoint();
                Mat templateDescriptors = new Mat();
                Mat screenDescriptors = new Mat();

                orb.DetectAndCompute(templateImage, null, templateKeypoints, templateDescriptors, false);
                orb.DetectAndCompute(screenCapture, null, screenKeypoints, screenDescriptors, false);

                if (templateKeypoints.Size == 0 || screenKeypoints.Size == 0)
                     showinfo("未检测到关键点");

                // 5. 使用 BFMatcher 进行暴力匹配
                // 创建匹配器
                BFMatcher matcher = new BFMatcher(DistanceType.Hamming);
                matcher.Add(templateDescriptors);

                // 使用 VectorOfVectorOfDMatch 替代 VectorOfDMatch
                VectorOfVectorOfDMatch knnMatches = new VectorOfVectorOfDMatch();
                matcher.KnnMatch(screenDescriptors, knnMatches, 2); // k=2 表示每个查询点找两个最近邻

                // 筛选好匹配（Lowe's Ratio Test）
                List<MDMatch> goodMatches = new List<MDMatch>();
                const float ratioThresh = 0.75f;

                for (int i = 0; i < knnMatches.Size; i++)
                {
                    if (knnMatches[i].Size >= 2)
                    {
                        MDMatch m1 = knnMatches[i][0];
                        MDMatch m2 = knnMatches[i][1];

                        if (m1.Distance < ratioThresh * m2.Distance)
                        {
                            goodMatches.Add(m1);
                        }
                    }
                }

                if (goodMatches.Count < 10)
                    showinfo("匹配点过少，无法定位目标");

                // 7. 获取匹配点坐标
                PointF[] templatePoints = new PointF[goodMatches.Count];
                PointF[] screenPoints = new PointF[goodMatches.Count];

                for (int i = 0; i < goodMatches.Count; i++)
                {
                    int trainIdx = goodMatches[i].TrainIdx; // 模板图中的索引
                    int queryIdx = goodMatches[i].QueryIdx; // 屏幕图中的索引

                    templatePoints[i] = templateKeypoints[trainIdx].Point;
                    screenPoints[i] = screenKeypoints[queryIdx].Point;
                }

                // 8. 计算单应性矩阵（Homography）
                using (Mat homography = CvInvoke.FindHomography(
    templatePoints,
    screenPoints,
    RobustEstimationAlgorithm.Ransac, 
    3,
    null))
                {
                    if (homography.IsEmpty)
                        showinfo("无法计算单应性矩阵" );

                    // 9. 根据模板图像边界投影到屏幕图像上
                    Rectangle rect = new Rectangle(Point.Empty, templateImage.Size);
                    PointF[] corners = new PointF[]
                    {
                new Point(rect.Left, rect.Top),
                new Point(rect.Right, rect.Top),
                new Point(rect.Right, rect.Bottom),
                new Point(rect.Left, rect.Bottom)
                    };

                    PointF[] transformedCorners = CvInvoke.PerspectiveTransform(corners, homography);

                    // 10. 获取包围匹配区域的矩形
                    int xMin = (int)transformedCorners.Min(p => p.X);
                    int yMin = (int)transformedCorners.Min(p => p.Y);
                    int xMax = (int)transformedCorners.Max(p => p.X);
                    int yMax = (int)transformedCorners.Max(p => p.Y);

                    int margin = 80;
                    Rectangle matchRect = new Rectangle(
                        Math.Max(0, xMin - margin),
                        Math.Max(0, yMin - margin),
                        Math.Min(xMax - xMin + 2 * margin, screenCapture.Width - (xMin - margin)),
                        Math.Min(yMax - yMin + 2 * margin, screenCapture.Height - (yMin - margin))
                    );

                    // 11. 安全裁剪区域
                    Rectangle safeRect = new Rectangle(
                        Math.Max(0, matchRect.X),
                        Math.Max(0, matchRect.Y),
                        Math.Min(matchRect.Width, screenCapture.Width - matchRect.X),
                        Math.Min(matchRect.Height, screenCapture.Height - matchRect.Y)
                    );

                    // 12. 裁剪出目标区域
                    // ... existing code ...
                    using (Mat questionArea = new Mat(screenCapture, safeRect))
                    {
                        // 将图像数据保存到内存流
                        using (MemoryStream ms = new MemoryStream())
                        {
                            // 将Mat转换为Bitmap并保存到内存流
                            Bitmap bitmap = questionArea.ToBitmap();
                            bitmap.Save(ms, ImageFormat.Jpeg);

                            // 将内存流的位置重置为开头
                            ms.Position = 0;

                            // 创建全局变量存储图像数据
                            imageData = ms.ToArray();
                        }

                        // 更新图片框显示
                        pictureBox.Image = questionArea.ToBitmap();
                    }
                }
            }
            catch (Exception ex)
            {
                showinfo("特征匹配或图像裁剪过程中发生异常"+ ex.Message);
                //throw new ApplicationException(@"特征匹配或图像裁剪过程中发生异常。", ex);
            }
        }

        private void showinfo(string strInfo)
        {
            if (textBox1.InvokeRequired)
            {
                textBox1.Invoke(new MethodInvoker(delegate {
                    textBox1.Text = strInfo;
                }));
            }
            else
            {
                textBox1.Text = strInfo;
            }
        }
        public static Mat CaptureScreen()
        {
            // 获取主屏幕的工作区域
            Rectangle screenBounds = Screen.PrimaryScreen.WorkingArea;

            int screenWidth = screenBounds.Width;
            int screenHeight = screenBounds.Height;

            // 计算尺寸
            int iWidth = screenWidth / 3;                   // 左侧三分之一宽度
            int iHeight = (3 * screenHeight) / 4;           // 四分之三高度

            using (Bitmap bitmap = new Bitmap(iWidth, iHeight, PixelFormat.Format32bppArgb))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(0, 0, 0, 0, new Size(iWidth, iHeight), CopyPixelOperation.SourceCopy);
                }

                // 返回 Mat 格式
                return bitmap.ToMat();
            }
        }
        private void button3_Click(object sender, EventArgs e)
        {
            InitData();
            MessageBox.Show(@"重新读取题库数据完成！");
        }

        private void InitData()
        {
            var getJson = GetJsonFile("data.json");
            var dt = ToDataTable(getJson);
            dataGridView1.DataSource = dt;
        }

        private static string GetJsonFile(string filepath)
        {
            string json;
            using (var fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                using (var sr = new StreamReader(fs, Encoding.UTF8))
                {
                    json = sr.ReadToEnd();
                }
            }
            return json;
        }

        public static DataTable ToDataTable(string json)
        {
            var dataTable = new DataTable();
            dataTable.Columns.Add("id");
            dataTable.Columns.Add("q");
            dataTable.Columns.Add("a");
            dataTable.Columns.Add("py");
            dataTable.Columns.Add("l");

            try
            {
                // 检查并修正 JSON 字符串中的非法转义字符
                //string correctedJson = json.Replace("\"\"", "\"\\\"");

                using (JsonDocument doc = JsonDocument.Parse(json))
                {
                    JsonElement root = doc.RootElement;

                    if (root.ValueKind == JsonValueKind.Array)
                    {
                        foreach (JsonElement item in root.EnumerateArray())
                        {
                            if (item.ValueKind != JsonValueKind.Object)
                                continue;

                            var dataRow = dataTable.NewRow();

                            foreach (JsonProperty property in item.EnumerateObject())
                            {
                                string key = property.Name;
                                JsonElement value = property.Value;

                                if (key == "l" && value.ValueKind == JsonValueKind.Array)
                                {
                                    // 处理数组字段 "l"
                                    var list = new List<string>();
                                    foreach (var arrayItem in value.EnumerateArray())
                                    {
                                        list.Add(arrayItem.ToString());
                                    }
                                    dataRow[key] = string.Join(",", list);
                                }
                                else
                                {
                                    // 其他字段直接转为字符串
                                    dataRow[key] = value.ToString();
                                }
                            }

                            dataTable.Rows.Add(dataRow);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

            return dataTable;
        }

        private bool bEnable;
        private void button4_Click(object sender, EventArgs e)
        {
            strOldQ = string.Empty;
            strOldA = string.Empty;

            bEnable = !bEnable;
            if (bEnable)
            {
                label18.Text = @"已开启自动解析";
                button4.Text = @"关闭自动解析提示";
            }
            else
            {
                label18.Text = @"已关闭自动解析";
                button4.Text = @"开启自动解析提示";

                var messageForm = MessageForm.CreateForm();
                SafeCloseForm(messageForm);
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            GetAns();
        }

        private void textBox2_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                GetAns();
            }
        }

        private void 给作者打钱ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var about = new About();
            about.ShowDialog();
        }

        private void BtnManualParsing_Click(object sender, EventArgs e)
        {
            if (BtnManualParsing.Text == @"展开手动解析⬇")
            {
                // 1011, 673
                BtnManualParsing.Text = @"收起手动解析⬆";
                Width = (int)(1547 * scalingFactor);
                Height = (int)(950 * scalingFactor);
            }
            else
            {
                BtnManualParsing.Text = @"展开手动解析⬇";
                Width = (int)(1045 * scalingFactor);
                Height = (int)(391 * scalingFactor);


                // 736, 279
            }
        }

        private void 设置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var optionForm = new OptionForm();
            optionForm.ShowDialog();
        }

        private void 高级设置慎用ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var sensitiveOptionForm = new SensitiveOptionForm();
            sensitiveOptionForm.ShowDialog();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var optionForm = new OptionForm();
            optionForm.ShowDialog();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            var sensitiveOptionForm = new SensitiveOptionForm();
            sensitiveOptionForm.ShowDialog();
        }

        private void button7_Click(object sender, EventArgs e)
        {
            var about = new About();
            about.ShowDialog();
        }

        private void buttonSZ_Click(object sender, EventArgs e)
        {
            var optionForm = new OptionForm();
            optionForm.ShowDialog();
        }
    }
}
